use crate::cache::IndexChange;
use crate::keys::VddKey;
use crate::record_db::RecordDbTrait;
use crate::{
    cache, load_by_key_head_with_key, model_db, query_db, record_db, record_rule_db, subscribe,
    user_db, value_db, visit_db, ROCKSDB,
};
use rust_rocksdb::WriteBatchWithTransaction;
use serde_json::Value;
use std::collections::HashMap;
use std::sync::Arc;
use visit_dd_core::gateway::{ClientToken, RecordAction, C_TT_ANO, C_TT_PK, C_TT_VC};
use visit_dd_core::model::{VddModel, VddSchema};
use visit_dd_core::query::{
    QueryDataPage, QueryFilter, ShareQueryParams, VddValueEvaluation, WebQueryParams,
};
use visit_dd_core::record::VddRecord;
use visit_dd_core::value::VddValue;
use visit_dd_core::visit::{VisitGroup, VisitGroupType};
use visit_dd_core::{
    extract_u64_from_key, i18n, is_sub_vec, ActionReturnMessage, Ares, Astr, FieldId, RecordId,
    AC_ADD, EMPTY_RID,
};

/// 尝试查找匹配的访问组
pub async fn try_to_vg(token: &ClientToken, model: &VddModel) -> Option<Arc<VisitGroup>> {
    let mut r: Option<Arc<VisitGroup>> = None;
    for vg in visit_db::vg_select_in_model(model.id).await.iter() {
        match vg.group_type.as_ref() {
            VisitGroupType::VgtAnonymous => {
                if token.token_type == C_TT_ANO {
                    r = Some(vg.clone());
                }
            }
            VisitGroupType::VgtPubKey => {
                let user = user_db::u_load(&vg.u_id, false, true).await;
                if token.token_type == C_TT_PK {
                    let hash = format!(
                        "{}{:?}",
                        user.pub_key,
                        token.salt.expect("client token error in salt")
                    );
                    if token.eq_hash(&hash) {
                        r = Some(vg.clone());
                    }
                }
            }
            VisitGroupType::VgtCode { k, c } => {
                if token.token_type == C_TT_VC {
                    let hash = format!(
                        "{}{:?}{:?}",
                        k,
                        c,
                        token.salt.expect("client token error in salt")
                    );
                    if token.eq_hash(&hash) {
                        r = Some(vg.clone());
                    }
                }
            }
            _ => {}
        }
    }
    if r.is_none() && token.token_type == C_TT_PK {
        // 如果没找到，看是不是作者
        let user = user_db::u_load(&model.uid, false, false).await;
        let hash = format!("{}{:?}", user.pub_key, token.salt.unwrap());
        // tracing::info!(hash);
        if token.eq_hash(&hash) {
            r = Some(VisitGroup::fake_author_vg(model).into());
        }
    }
    r
}
///
pub async fn try_to_schema(
    j: &Value,
    model_tag: &str,
    check_field_tag: bool,
) -> Result<Arc<VddSchema>, Astr> {
    let model = model_db::m_load_by_tag(model_tag).await;
    if model.is_none() {
        return Err(Arc::from("传入的模型标记错误"));
    }
    let model = model.unwrap();
    let schema = cache::get_schema(model.id).await?;
    if check_field_tag {
        let field_tags: Vec<Arc<str>> = j["fields"]
            .as_array()
            .unwrap()
            .iter()
            .map(|x| Arc::from(x.as_str().unwrap()))
            .collect();
        if field_tags.len() < 1 {
            return Err(Arc::from("传入的字段标记错误"));
        } else {
            if !is_sub_vec(&field_tags, &schema.tags) {
                return Err(Arc::from("传入的字段标记错误"));
            }
        }
    }
    Ok(schema)
}

/// 将网关的查询参数转换成id形式的查询参数
// async fn gateway_query_to_web_query(
//     schema: &VddSchema,
//     gqfs: &[Arc<GatewayQueryFilter>],
// ) -> Vec<Arc<QueryFilter>> {
//     let mut r = Vec::<Arc<QueryFilter>>::with_capacity(gqfs.len());
//     for x in gqfs.iter() {
//         let qf_ref = match x.as_ref() {
//             GatewayQueryFilter::GqfUsers(u) => {
//                 let mut uids = Vec::<UserId>::new();
//                 for y in u.iter() {
//                     let uid = user_db::u_select_by_phone(&y).await.unwrap().id;
//                     uids.push(uid);
//                 }
//                 QueryFilter::QfCommiters(uids).into()
//             }
//             GatewayQueryFilter::GqfUtsRange(b_date, e_date) => {
//                 QueryFilter::QfUtsRange(b_date.clone(), e_date.clone()).into()
//             }
//             GatewayQueryFilter::GqfEqual(f_tag, arg) => {
//                 let fid = schema.tags.iter().find(|y| y.1.eq(f_tag)).unwrap().0;
//                 QueryFilter::QfFiledValue(
//                     VddValueEvaluation::FveEqual(FieldId(*fid), arg.clone()).into(),
//                 )
//                 .into()
//             }
//             GatewayQueryFilter::GqfNotEqual(f_tag, arg) => {
//                 let fid = schema.tags.iter().find(|y| y.1.eq(f_tag)).unwrap().0;
//                 QueryFilter::QfFiledValue(
//                     VddValueEvaluation::FvePartialMatch(FieldId(*fid), arg.clone()).into(),
//                 )
//                 .into()
//             }
//             GatewayQueryFilter::GqfPartialMatch(f_tag, arg) => {
//                 let fid = schema.tags.iter().find(|y| y.1.eq(f_tag)).unwrap().0;
//                 QueryFilter::QfFiledValue(
//                     VddValueEvaluation::FvePartialMatch(FieldId(*fid), arg.clone()).into(),
//                 )
//                 .into()
//             }
//             GatewayQueryFilter::GqfNotContains(f_tag, arg) => {
//                 let fid = schema.tags.iter().find(|y| y.1.eq(f_tag)).unwrap().0;
//                 QueryFilter::QfFiledValue(
//                     VddValueEvaluation::FveNotContains(FieldId(*fid), arg.clone()).into(),
//                 )
//                 .into()
//             }
//             GatewayQueryFilter::GqfBetween(f_tag, arg1, arg2) => {
//                 let fid = schema.tags.iter().find(|y| y.1.eq(f_tag)).unwrap().0;
//                 QueryFilter::QfFiledValue(
//                     VddValueEvaluation::FveBetween(FieldId(*fid), arg1.clone(), arg2.clone())
//                         .into(),
//                 )
//                 .into()
//             }
//             GatewayQueryFilter::GqfOutRange(f_tag, arg1, arg2) => {
//                 let fid = schema.tags.iter().find(|y| y.1.eq(f_tag)).unwrap().0;
//                 QueryFilter::QfFiledValue(
//                     VddValueEvaluation::FveOutRange(FieldId(*fid), arg1.clone(), arg2.clone())
//                         .into(),
//                 )
//                 .into()
//             }
//             GatewayQueryFilter::GqfIn(f_tag, args) => {
//                 let fid = schema.tags.iter().find(|y| y.1.eq(f_tag)).unwrap().0;
//                 QueryFilter::QfFiledValue(
//                     VddValueEvaluation::FveIn(FieldId(*fid), args.clone()).into(),
//                 )
//                 .into()
//             }
//             GatewayQueryFilter::GqfExclude(f_tag, args) => {
//                 let fid = schema.tags.iter().find(|y| y.1.eq(f_tag)).unwrap().0;
//                 QueryFilter::QfFiledValue(
//                     VddValueEvaluation::FveExclude(FieldId(*fid), args.clone()).into(),
//                 )
//                 .into()
//             }
//             GatewayQueryFilter::GqfStartWith(f_tag, arg) => {
//                 let fid = schema.tags.iter().find(|y| y.1.eq(f_tag)).unwrap().0;
//                 QueryFilter::QfFiledValue(
//                     VddValueEvaluation::FveStartWith(FieldId(*fid), arg.clone()).into(),
//                 )
//                 .into()
//             }
//             GatewayQueryFilter::GqfEndWith(f_tag, arg) => {
//                 let fid = schema.tags.iter().find(|y| y.1.eq(f_tag)).unwrap().0;
//                 QueryFilter::QfFiledValue(
//                     VddValueEvaluation::FveEndWith(FieldId(*fid), arg.clone()).into(),
//                 )
//                 .into()
//             }
//         };
//         r.push(Arc::new(qf_ref));
//     }
//     r
// }

/// 从上传json中生成访问请求
pub async fn sqp_from_gateway_json(
    j: &Value,
    token: &ClientToken,
    model_tag: &str,
    check_fields: bool,
) -> Result<ShareQueryParams, Astr> {
    let schema = try_to_schema(j, model_tag, check_fields).await?;
    let mut params = WebQueryParams::try_from(j)?;
    params.filters = QueryFilter::batch_from_json(j);
    let vg = try_to_vg(token, &schema.model).await;
    if vg.is_none() {
        return Err(i18n!(1356));
    }
    let vg = vg.unwrap();
    Ok(ShareQueryParams {
        schema,
        vg,
        params: Arc::new(params),
    })
}

/// 通过网关查询数据
pub async fn get_page_for_gateway(sqp: &ShareQueryParams) -> QueryDataPage<Value> {
    let index_key = VddKey::IndexModel2Record(sqp.schema.model.id).to_string();
    let mut ids = cache::get_index(&index_key);
    if sqp.params.new_to_old {
        ids.reverse();
    }
    let page = query_db::select_records_in_index(sqp, &ids).await;
    QueryDataPage {
        data: page
            .data
            .iter()
            .map(|rec| {
                Arc::new(rec.to_json(
                    &sqp.schema.tags,
                    sqp.vg.group_type.as_ref() == &VisitGroupType::VgtVirtualAuthor,
                ))
            })
            .collect::<Vec<Arc<Value>>>(),
        all_record_count: page.all_record_count,
        last_index: page.last_index,
    }
}

/// 查询某个列值，从中找出符合条件的记录主键
fn get_rec_ids_by_filter(filter: &VddValueEvaluation) -> Result<Vec<RecordId>, Astr> {
    let kh = VddKey::BoundFieldValue(filter.get_field_id(), EMPTY_RID);
    let mut r = Vec::<RecordId>::new();
    load_by_key_head_with_key(&kh).iter().for_each(|x| {
        let fv = serde_json::from_slice::<VddValue>(&x.1).unwrap();
        if filter.evaluate(&fv) {
            let id = extract_u64_from_key(&x.0);
            r.push(RecordId(id));
        }
    });
    // println!("{:?}", r);
    Ok(r)
}

/// 专门用于比对某个字段等于某个值的记录是否存在,利用缓存加速
pub fn check_exist(fid: &FieldId, arg: Astr) -> bool {
    let fvs = value_db::fv_select_all(fid);
    match fvs {
        Err(_) => false,
        Ok(fvs) => fvs
            .iter()
            .find(|vvm| vvm.value.get_simple_display() == arg)
            .is_some(),
    }
}

/// 检验符合查询条件的记录是否存在
pub async fn check_record_exist(model_tag: &str, filters: &[Arc<QueryFilter>]) -> Result<(), Astr> {
    let model = model_db::m_load_by_tag(model_tag).await;
    if model.is_none() {
        return Err("传入的模型标记错误".into());
    }
    // 看看是否能用缓存加速
    if filters.len() == 1 {
        let filter = filters.get(0).unwrap();
        if let Some(filter) = filter.as_vdd_fve() {
            if let Some(arg) = filter.get_equal_compare_arg() {
                return if check_exist(&filter.get_field_id(), arg) {
                    Ok(())
                } else {
                    Err("Not exist".into())
                };
            }
        }
    }
    let mut id_map = HashMap::<u64, u64>::new();
    filters.iter().for_each(|x| {
        if let Some(filter) = x.as_vdd_fve() {
            if let Ok(ids) = get_rec_ids_by_filter(&filter) {
                ids.iter().for_each(|rec_id| {
                    if !id_map.contains_key(&rec_id.0) {
                        id_map.insert(rec_id.0, 0);
                    }
                    id_map.insert(rec_id.0, *id_map.get(&rec_id.0).unwrap() + 1);
                });
            }
        }
    });
    id_map.retain(|_, v| *v == filters.len() as u64);
    if id_map.is_empty() {
        Err("Empty result set".into())
    } else {
        Ok(())
    }
}

///
pub async fn execute_gateway_actions(
    actions: &[RecordAction],
    schema: &VddSchema,
    vg: &VisitGroup,
) -> Vec<ActionReturnMessage<()>> {
    let v_rules = record_rule_db::rr_select_in_model(schema.model.id).await;
    let mut r = Vec::<ActionReturnMessage<()>>::new();
    for action in actions {
        let ares = match action.a {
            visit_dd_core::AC_DELETE => {
                record_db::delete(&action.rec_id, schema, vg.u_id.clone()).await
            }
            visit_dd_core::AC_DELETE_ATTR => {
                let p_fid = action.f_id.clone().unwrap();
                value_db::fv_delete(&p_fid, &action.rec_id, schema, &v_rules).await
            }
            visit_dd_core::AC_EDIT | visit_dd_core::AC_EDIT_ITEM | visit_dd_core::AC_EDIT_ATTR => {
                let p_fid = action.f_id.clone().unwrap();
                let field = schema
                    .fields
                    .iter()
                    .find(|f| f.id == p_fid)
                    .unwrap()
                    .clone();
                let fv_new = Arc::new(VddValue::from_json(
                    &field,
                    &action.v.clone().unwrap(),
                    &vg.u_id,
                ));
                value_db::fv_update(&p_fid, &action.rec_id, fv_new, schema, &v_rules)
            }
            visit_dd_core::AC_ADD_ITEM => {
                let p_fid = action.f_id.clone().unwrap();
                let mut fv_o = value_db::fv_load(&p_fid, &action.rec_id).unwrap();
                fv_o.add_item(action.v.clone().unwrap().as_str().unwrap())
                    .unwrap();
                value_db::fv_update(&p_fid, &action.rec_id, Arc::new(fv_o), schema, &v_rules)
            }
            visit_dd_core::AC_DELETE_ITEM => {
                let p_fid = action.f_id.clone().unwrap();
                let mut fv_o = value_db::fv_load(&p_fid, &action.rec_id).unwrap();
                fv_o.remove_item(action.v.clone().unwrap().as_str().unwrap())
                    .unwrap();
                value_db::fv_update(&p_fid, &action.rec_id, Arc::new(fv_o), schema, &v_rules)
            }
            visit_dd_core::AC_EDIT_ITEM_BY_INDEX => {
                let p_fid = action.f_id.clone().unwrap();
                let mut fv_o = value_db::fv_load(&p_fid, &action.rec_id).unwrap();
                fv_o.change_item(
                    action.idx.cast_unsigned(),
                    action.v.clone().unwrap().as_str().unwrap(),
                )
                .unwrap();
                value_db::fv_update(&p_fid, &action.rec_id, Arc::new(fv_o), schema, &v_rules)
            }
            _ => panic!("未知的数据操作代码"),
        };
        r.push(ActionReturnMessage::from_ares(ares));
    }
    r
}

/// 批量保存多条记录
pub async fn append_some(
    schema: &VddSchema,
    records: &mut [VddRecord],
    vg: &VisitGroup,
) -> Vec<Ares> {
    let mut r = Vec::<Ares>::new();
    let rrs = record_rule_db::rr_select_in_model(schema.model.id).await;
    if !vg.write_able {
        r.push(Err("模型没有开放此访问者的写数据权限".into()));
        return r;
    }
    let mut batch = WriteBatchWithTransaction::<true>::new();
    let mut index_changes = Vec::<IndexChange>::new();
    for mut record in records.iter_mut() {
        //
        let result = record.fit_field_defines(&schema, false);
        if result.is_err() {
            r.push(result);
            continue;
        }
        //
        let result = record.fit_record_rules(&schema, &rrs, false).await;
        if result.is_err() {
            r.push(result);
            continue;
        }
        let result = record_db::save(&mut record, schema, &rrs, true).await;
        if result.is_err() {
            r.push(result);
            continue;
        }
        subscribe::send_change_event(
            &mut batch,
            &mut index_changes,
            schema.model.id,
            &record.meta.id,
            AC_ADD,
        );
        r.push(result);
    }
    ROCKSDB.write(batch).unwrap();
    cache::apply_index_change(&index_changes).unwrap();
    r
}
